First of all, we need to install some packages. Remember that dplyr lives in the tidyverse:
install.packages("tidyverse")
install.packages("knitr")
install.packages("scales")
install.packages("ggthemes")
install.packages("highcharter")
And since this is a Pokemon-based exercise, let’s also install some Pokemon-related color palettes:
install.packages('palettetown')
Let’s load all packages:
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages -------------------------------------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
library(knitr)
library(scales)
Attaching package: ‘scales’
The following object is masked from ‘package:purrr’:
discard
The following object is masked from ‘package:readr’:
col_factor
library(ggthemes)
library(palettetown)
library(highcharter, quietly = TRUE)
Highcharts (www.highcharts.com) is a Highsoft software product which is
not free for commercial and Governmental use
library(rvest)
Loading required package: xml2
Attaching package: ‘rvest’
The following object is masked from ‘package:readr’:
guess_encoding
Now, let’s load that freely available Pokemon dataset!
data_file <- 'https://assets.datacamp.com/production/course_1815/datasets/Pokemon.csv'
data <- read_csv(data_file)
Parsed with column specification:
cols(
Number = col_integer(),
Name = col_character(),
Type1 = col_character(),
Type2 = col_character(),
Total = col_integer(),
HitPoints = col_integer(),
Attack = col_integer(),
Defense = col_integer(),
SpecialAttack = col_integer(),
SpecialDefense = col_integer(),
Speed = col_integer(),
Generation = col_integer(),
Legendary = col_character()
)
And some more things happening under da hood:
r_90_d <- theme(axis.text.x = element_text(angle = 90, hjust = 1))
caption <- "RLadies Munich"
my_theme <- theme_few()
We also need some Pokemon- and RLadies- related colors. Rattata seems to have a nice color scheme similar to both. We’ll use the %>% (pipe) operator from the magritte package (don’t worry. The tidyverse already includes it):
cp_rattata <- "Rattata" %>% ichooseyou(spread = 13)
cp <- c(cp_rattata, cp_rattata)
We read that as “Rattata! I choose you!” (well, only thirteen distinct colors, hence spread = 13, but you get the point).
If we’re not trying to choose a color palette, we read the %>% operator as ‘then’, but more on that below.
Let’s now take a look at how our dataset looks:
head(data)
As the dataset’s website explains, this a dataset containing 13 variables:
- Number: ID for each pokemon
- Name: Name of each pokemon
- Type1: Each pokemon has a type, this determines weakness/resistance to attacks
- Type2: Some pokemon are dual type and have 2
- Total: sum of all stats that come after this, a general guide to how strong a pokemon is
- HitPoints: hit points, or health, defines how much damage a pokemon can withstand before fainting
- Attack: the base modifier for normal attacks (eg. Scratch, Punch)
- Defense: the base damage resistance against normal attacks
- SpecialAttack: special attack, the base modifier for special attacks (e.g. fire blast, bubble beam)
- SpecialDefense: the base damage resistance against special attacks
- Speed: determines which pokemon attacks first each round
- Generation: the number of the generation (as an integer) each pokemon belongs to.
- Legendary: whether the pokemon is legendary or not, as a boolean value.
Verbs for columns: select() and mutate()
Selecting columns using select()
The first dplyr verb we’ll use is select(). It allows us to select only columns that we’re interested in, without creating subsets of the dataset or losing information. Let’s suppose that we want to visualize only the Number of the Pokemon, its Name and whether or not it is Legendary:
data %>%
select(Number, Name, Legendary)
The verb select() also allows to choose columns by number:
data %>%
select(1:2,13)
Mutating columns using mutate()
There is one column called Total which is described as “sum of all stats that come after this, a general guide to how strong a pokemon is.” Let’s verify this information summing up all the stats to mutate() this information into a new variable called Total2:
data %>%
mutate(Total2 = HitPoints + Attack + Defense + SpecialAttack + SpecialDefense + Speed)
As we can see, mutate() makes it easy to work with the information contained in variables in order to create a completely new variable.
Verbs for rows: filter() and arrange()
Filtering rows with filter()
Which Pokemons are water type? Which are fire type? We can find out by using filter().
data %>%
filter(Type1 == "Water")
data %>%
filter(Type1 == "Fire")
Other verbs: summarise() and group_by()
There are at least two other verbs in dplyr which are quite useful. If we want to get summary statistics, we can use summarise() + the summarizing function we need. Plus, sometimes we need to analyze data by groups. This is where group_by() comes into play. Let’s use these two verbs at once to get the mean() and standard deviation sd() of the Total by Type1 of Pokemon, as well as how many there are by using n(), and then using arrange() to see which types are on the first positions:
data %>%
group_by(Type1) %>%
summarise(n = n(),
avg_total = mean(Total),
sd_total = sd(Total)) %>%
arrange(desc(avg_total))
Dragon type is the best!
How many Pokemons are per type?
Let’s use some dplyr functions and ggplot to create a barchart of Pokemon types!
data %>%
count(Type1) %>%
mutate(Type1 = forcats::fct_reorder(Type1, n, .desc = FALSE)) %>%
ggplot(aes(x = Type1, y = n)) +
geom_bar(stat = 'identity', aes(fill = Type1)) +
my_theme +
coord_flip() +
scale_fill_manual(values = cp, guide = FALSE)

NA
Exercises
- Use the
filter function to select only the water Pokemons and save it in an object called water.
- Do the same with the fire Pokemons and save it in an object called
fire.
- Which type is more powerful? Calculate the average
Total score of each type of Pokemon. Use na.rm = TRUE. Do not use the %>% operator.
- Try to get to the same result in one pipeline by using
group_by, filter and summarize.
Solutions
- Use the
filter function to select only the water Pokemons and save it in an object called water.
water <- data %>%
filter(Type1 == "Water")
water
- Do the same with the fire Pokemons and save it in an object called
fire.
fire <- data %>%
filter(Type1 == "Fire")
fire
fire <- data %>%
filter(Type1 == "Fire")
fire
- Which type is more powerful? Calculate the average
Total score of each type of Pokemon. Use na.rm = TRUE. Do not use the %>% operator.
mean(water$Total, na.rm = TRUE)
[1] 430.4554
mean(fire$Total, na.rm = TRUE)
[1] 458.0769
- Try to get to the same result in one pipeline by using
filter, group_by and summarize.
data %>%
filter(Type1 == "Water" | Type1 == "Fire") %>%
group_by(Type1) %>%
summarise(mean(Total, na.rm = TRUE))
Congrats! You’ve learned dplyr!
LS0tCnRpdGxlOiAiZHBseXIgZm9yIGV4cGxvcmluZyBQb2tlbW9uIGRhdGEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiFbXShodHRwczovL21lZGlhLmdpcGh5LmNvbS9tZWRpYS9CaW04UFR4eUJ1cmZpL2dpcGh5LmdpZikKCkZpcnN0IG9mIGFsbCwgd2UgbmVlZCB0byBpbnN0YWxsIHNvbWUgcGFja2FnZXMuIFJlbWVtYmVyIHRoYXQgYGRwbHlyYCBsaXZlcyBpbiB0aGUgYHRpZHl2ZXJzZWA6CmBgYCB7ciBldmFsID0gRkFMU0UsIGVycm9yID0gRkFMU0V9Cmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpIAppbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpCmluc3RhbGwucGFja2FnZXMoInNjYWxlcyIpCmluc3RhbGwucGFja2FnZXMoImdndGhlbWVzIikKaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQpgYGAKCkFuZCBzaW5jZSB0aGlzIGlzIGEgUG9rZW1vbi1iYXNlZCBleGVyY2lzZSwgbGV0J3MgYWxzbyBpbnN0YWxsIHNvbWUgUG9rZW1vbi1yZWxhdGVkIGNvbG9yIHBhbGV0dGVzOgoKYGBgIHtyIGV2YWwgPSBGQUxTRSwgZXJyb3IgPSBGQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygncGFsZXR0ZXRvd24nKQpgYGAKCkxldCdzIGxvYWQgYWxsIHBhY2thZ2VzOgpgYGAge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShwYWxldHRldG93bikKbGlicmFyeShoaWdoY2hhcnRlciwgcXVpZXRseSA9IFRSVUUpCmxpYnJhcnkocnZlc3QpCmBgYAoKTm93LCBsZXQncyBsb2FkIHRoYXQgZnJlZWx5IGF2YWlsYWJsZSBbUG9rZW1vbiBkYXRhc2V0XShodHRwczovL3d3dy5rYWdnbGUuY29tL2FiY3Nkcy9wb2tlbW9uKSEKYGBge3J9CmRhdGFfZmlsZSA8LSAnaHR0cHM6Ly9hc3NldHMuZGF0YWNhbXAuY29tL3Byb2R1Y3Rpb24vY291cnNlXzE4MTUvZGF0YXNldHMvUG9rZW1vbi5jc3YnCmRhdGEgPC0gcmVhZF9jc3YoZGF0YV9maWxlKQpgYGAKCkFuZCBzb21lIG1vcmUgdGhpbmdzIGhhcHBlbmluZyB1bmRlciBkYSBob29kOgpgYGAge3J9CnJfOTBfZCA8LSB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQpjYXB0aW9uIDwtICJSTGFkaWVzIE11bmljaCIKbXlfdGhlbWUgPC0gdGhlbWVfZmV3KCkgCmBgYAoKV2UgYWxzbyBuZWVkIHNvbWUgUG9rZW1vbi0gYW5kIFJMYWRpZXMtIHJlbGF0ZWQgY29sb3JzLiBSYXR0YXRhIHNlZW1zIHRvIGhhdmUgYSBuaWNlIGNvbG9yIHNjaGVtZSBzaW1pbGFyIHRvIGJvdGguIFdlJ2xsIHVzZSB0aGUgYCU+JWAgKHBpcGUpIG9wZXJhdG9yIGZyb20gdGhlIGBtYWdyaXR0ZWAgcGFja2FnZSAoZG9uJ3Qgd29ycnkuIFRoZSBgdGlkeXZlcnNlYCBhbHJlYWR5IGluY2x1ZGVzIGl0KToKYGBgIHtyfQpjcF9yYXR0YXRhIDwtICJSYXR0YXRhIiAlPiUgaWNob29zZXlvdShzcHJlYWQgPSAxMykKY3AgPC0gYyhjcF9yYXR0YXRhLCBjcF9yYXR0YXRhKQpgYGAKCldlIHJlYWQgdGhhdCBhcyAiUmF0dGF0YSEgSSBjaG9vc2UgeW91ISIgKHdlbGwsIG9ubHkgdGhpcnRlZW4gZGlzdGluY3QgY29sb3JzLCBoZW5jZSBgc3ByZWFkID0gMTNgLCBidXQgeW91IGdldCB0aGUgcG9pbnQpLgoKSWYgd2UncmUgbm90IHRyeWluZyB0byBjaG9vc2UgYSBjb2xvciBwYWxldHRlLCB3ZSByZWFkIHRoZSBgJT4lYCBvcGVyYXRvciBhcyAndGhlbicsIGJ1dCBtb3JlIG9uIHRoYXQgYmVsb3cuCgpMZXQncyBub3cgdGFrZSBhIGxvb2sgYXQgaG93IG91ciBkYXRhc2V0IGxvb2tzOgpgYGB7cn0KaGVhZChkYXRhKQpgYGAKCkFzIHRoZSBbZGF0YXNldCdzIHdlYnNpdGVdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vYWJjc2RzL3Bva2Vtb24pIGV4cGxhaW5zLCB0aGlzIGEgZGF0YXNldCBjb250YWluaW5nIDEzIHZhcmlhYmxlczoKCiogKipOdW1iZXIqKjogSUQgZm9yIGVhY2ggcG9rZW1vbgoqICoqTmFtZSoqOiBOYW1lIG9mIGVhY2ggcG9rZW1vbgoqICoqVHlwZTEqKjogRWFjaCBwb2tlbW9uIGhhcyBhIHR5cGUsIHRoaXMgZGV0ZXJtaW5lcyB3ZWFrbmVzcy9yZXNpc3RhbmNlIHRvIGF0dGFja3MKKiAqKlR5cGUyKio6IFNvbWUgcG9rZW1vbiBhcmUgZHVhbCB0eXBlIGFuZCBoYXZlIDIKKiAqKlRvdGFsKio6IHN1bSBvZiBhbGwgc3RhdHMgdGhhdCBjb21lIGFmdGVyIHRoaXMsIGEgZ2VuZXJhbCBndWlkZSB0byBob3cgc3Ryb25nIGEgcG9rZW1vbiBpcwoqICoqSGl0UG9pbnRzKio6IGhpdCBwb2ludHMsIG9yIGhlYWx0aCwgZGVmaW5lcyBob3cgbXVjaCBkYW1hZ2UgYSBwb2tlbW9uIGNhbiB3aXRoc3RhbmQgYmVmb3JlIGZhaW50aW5nCiogKipBdHRhY2sqKjogdGhlIGJhc2UgbW9kaWZpZXIgZm9yIG5vcm1hbCBhdHRhY2tzIChlZy4gU2NyYXRjaCwgUHVuY2gpCiogKipEZWZlbnNlKio6IHRoZSBiYXNlIGRhbWFnZSByZXNpc3RhbmNlIGFnYWluc3Qgbm9ybWFsIGF0dGFja3MKKiAqKlNwZWNpYWxBdHRhY2sqKjogc3BlY2lhbCBhdHRhY2ssIHRoZSBiYXNlIG1vZGlmaWVyIGZvciBzcGVjaWFsIGF0dGFja3MgKGUuZy4gZmlyZSBibGFzdCwgYnViYmxlIGJlYW0pCiogKipTcGVjaWFsRGVmZW5zZSoqOiB0aGUgYmFzZSBkYW1hZ2UgcmVzaXN0YW5jZSBhZ2FpbnN0IHNwZWNpYWwgYXR0YWNrcwoqICoqU3BlZWQqKjogZGV0ZXJtaW5lcyB3aGljaCBwb2tlbW9uIGF0dGFja3MgZmlyc3QgZWFjaCByb3VuZAoqICoqR2VuZXJhdGlvbioqOiB0aGUgbnVtYmVyIG9mIHRoZSBnZW5lcmF0aW9uIChhcyBhbiBpbnRlZ2VyKSBlYWNoIHBva2Vtb24gYmVsb25ncyB0by4KKiAqKkxlZ2VuZGFyeSoqOiB3aGV0aGVyIHRoZSBwb2tlbW9uIGlzIGxlZ2VuZGFyeSBvciBub3QsIGFzIGEgYm9vbGVhbiB2YWx1ZS4KCi0tLQoKIyMgVmVyYnMgZm9yIGNvbHVtbnM6IGBzZWxlY3QoKWAgYW5kIGBtdXRhdGUoKWAKIyMjIFNlbGVjdGluZyBjb2x1bW5zIHVzaW5nIGBzZWxlY3QoKWAKVGhlIGZpcnN0IGBkcGx5cmAgdmVyYiB3ZSdsbCB1c2UgaXMgYHNlbGVjdCgpYC4gSXQgYWxsb3dzIHVzIHRvIHNlbGVjdCBvbmx5IGNvbHVtbnMgdGhhdCB3ZSdyZSBpbnRlcmVzdGVkIGluLCB3aXRob3V0IGNyZWF0aW5nIHN1YnNldHMgb2YgdGhlIGRhdGFzZXQgb3IgbG9zaW5nIGluZm9ybWF0aW9uLiBMZXQncyBzdXBwb3NlIHRoYXQgd2Ugd2FudCB0byB2aXN1YWxpemUgb25seSB0aGUgYE51bWJlcmAgb2YgdGhlIFBva2Vtb24sIGl0cyBgTmFtZWAgYW5kIHdoZXRoZXIgb3Igbm90IGl0IGlzIGBMZWdlbmRhcnlgOgpgYGAge3J9CmRhdGEgJT4lCiAgc2VsZWN0KE51bWJlciwgTmFtZSwgTGVnZW5kYXJ5KQpgYGAKClRoZSB2ZXJiIGBzZWxlY3QoKWAgYWxzbyBhbGxvd3MgdG8gY2hvb3NlIGNvbHVtbnMgYnkgbnVtYmVyOgpgYGAge3J9CmRhdGEgJT4lCiAgc2VsZWN0KDE6MiwgMTMpCmBgYAoKCiFbXShodHRwczovL21lZGlhLnRlbm9yLmNvbS9pbWFnZXMvYzczZDZiYTdkNWRiNzJiNWYxMmU1MWU0ZTdlMWQ0NTUvdGVub3IuZ2lmKQoKCiMjIyBNdXRhdGluZyBjb2x1bW5zIHVzaW5nIGBtdXRhdGUoKWAKVGhlcmUgaXMgb25lIGNvbHVtbiBjYWxsZWQgYFRvdGFsYCB3aGljaCBpcyBkZXNjcmliZWQgYXMgInN1bSBvZiBhbGwgc3RhdHMgdGhhdCBjb21lIGFmdGVyIHRoaXMsIGEgZ2VuZXJhbCBndWlkZSB0byBob3cgc3Ryb25nIGEgcG9rZW1vbiBpcy4iIExldCdzIHZlcmlmeSB0aGlzIGluZm9ybWF0aW9uIHN1bW1pbmcgdXAgYWxsIHRoZSBzdGF0cyB0byBgbXV0YXRlKClgIHRoaXMgaW5mb3JtYXRpb24gaW50byBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYFRvdGFsMmA6CmBgYHtyfQpkYXRhICU+JQogIG11dGF0ZShUb3RhbDIgPSBIaXRQb2ludHMgKyBBdHRhY2sgKyBEZWZlbnNlICsgU3BlY2lhbEF0dGFjayArIFNwZWNpYWxEZWZlbnNlICsgU3BlZWQpCmBgYAoKQXMgd2UgY2FuIHNlZSwgYG11dGF0ZSgpYCBtYWtlcyBpdCBlYXN5IHRvIHdvcmsgd2l0aCB0aGUgaW5mb3JtYXRpb24gY29udGFpbmVkIGluIHZhcmlhYmxlcyBpbiBvcmRlciB0byBjcmVhdGUgYSBjb21wbGV0ZWx5IG5ldyB2YXJpYWJsZS4KCi0tLQoKIyMgVmVyYnMgZm9yIHJvd3M6IGBmaWx0ZXIoKWAgYW5kIGBhcnJhbmdlKClgCiMjIyBGaWx0ZXJpbmcgcm93cyB3aXRoIGBmaWx0ZXIoKWAKV2hpY2ggUG9rZW1vbnMgYXJlIHdhdGVyIHR5cGU/IFdoaWNoIGFyZSBmaXJlIHR5cGU/IFdlIGNhbiBmaW5kIG91dCBieSB1c2luZyBgZmlsdGVyKClgLgoKYGBge3J9CmRhdGEgJT4lCiAgZmlsdGVyKFR5cGUxID09ICJXYXRlciIpCmBgYAoKYGBge3J9CmRhdGEgJT4lCiAgZmlsdGVyKFR5cGUxID09ICJGaXJlIikKYGBgCgoKIyMjIEFycmFuZ2luZyBpbmZvcm1hdGlvbiB1c2luZyBgYXJyYW5nZSgpYApXaGVuIHdlIHVzZWQgYHNlbGVjdCgpYCB0byBzZWUgdGhlIFBva2Vtb24gYE51bWJlcmAsIGl0cyBgTmFtZWAgYW5kIHdoZXRoZXIgb3Igbm90IHRoZXkgYXJlIGBMZWdlbmRhcnlgLCB3ZSBjb3VsZCBvbmx5IHNlZSBgRkFMU0VgIHJlc3VsdHMgaW4gdGhlIGJlZ2lubmluZy4gSG93IGFib3V0IHdlIHJlLWBhcnJhbmdlKClgIHRoZSBpbmZvcm1hdGlvbiB0byBzZWUgdGhvc2Ugd2hpY2ggYXJlIGBMZWdlbmRhcnlgIGZpcnN0PwoKYGBgIHtyfQpkYXRhICU+JQogIHNlbGVjdChOdW1iZXIsIE5hbWUsIExlZ2VuZGFyeSkgJT4lCiAgYXJyYW5nZSgpCmBgYAoKV2FpdCwgd2Ugd2FudGVkIHRoZSBgVFJVRWAgdmFsdWVzIGluIGBMZWdlbmRhcnlgIHRvIGNvbWUgZmlyc3QuIEJ5IGRlZmF1bHQsIGBhcnJhbmdlKClgIHNob3dzIHRoZSBpbmZvcm1hdGlvbiBpbiBhbHBoYWJldGljYWwgb3JkZXIgYS16LCBvciBudW1iZXIgb3JkZXIgZnJvbSBsb3dlc3QgdG8gaGlnaGVzdC4gV2hlbiBzaG93aW5nIGJvb2xlYW5zLCBpdCByZWxpZXMgb24gYEZBTFNFID0gMGAgYW5kIGBUUlVFID0gMWAsIHdoaWNoIG1lYW5zIHRoYXQgc2hvd3MgYEZBTFNFYCBmaXJzdCBieSBkZWZhdWx0LiBJZiB3ZSB3YW50IHRvIHJldmVyc2UgdGhpcyBhbmQgc2hvdyByZXN1bHRzIGluIGRlc2NlbmRpbmcgb3JkZXIsIHdlIGhhdmUgdG8gdXNlIGBkZXNjKClgLiBTbywgbm8gcHJvYmxlbSEgV2UgY2FuIGFzayBgYXJyYW5nZSgpYCB0byBzaG93IHJlc3VsdHMgaW4gZGVzY2VuZGluZyBvcmRlciBieSBpbmNsdWRpbmcgYGRlc2MoKWAgb24gYExlZ2VuZGFyeWA6CgpgYGB7cn0KZGF0YSAlPiUKICBzZWxlY3QoTnVtYmVyLCBOYW1lLCBMZWdlbmRhcnkpICU+JQogIGFycmFuZ2UoZGVzYyhMZWdlbmRhcnkpKQpgYGAKCiMjIE90aGVyIHZlcmJzOiBgc3VtbWFyaXNlKClgIGFuZCBgZ3JvdXBfYnkoKWAKVGhlcmUgYXJlIGF0IGxlYXN0IHR3byBvdGhlciB2ZXJicyBpbiBgZHBseXJgIHdoaWNoIGFyZSBxdWl0ZSB1c2VmdWwuIElmIHdlIHdhbnQgdG8gZ2V0IHN1bW1hcnkgc3RhdGlzdGljcywgd2UgY2FuIHVzZSBgc3VtbWFyaXNlKClgICsgdGhlIHN1bW1hcml6aW5nIGZ1bmN0aW9uIHdlIG5lZWQuIFBsdXMsIHNvbWV0aW1lcyB3ZSBuZWVkIHRvIGFuYWx5emUgZGF0YSBieSBncm91cHMuIFRoaXMgaXMgd2hlcmUgYGdyb3VwX2J5KClgIGNvbWVzIGludG8gcGxheS4gTGV0J3MgdXNlIHRoZXNlIHR3byB2ZXJicyBhdCBvbmNlIHRvIGdldCB0aGUgYG1lYW4oKWAgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBgc2QoKWAgb2YgdGhlIGBUb3RhbGAgYnkgYFR5cGUxYCBvZiBQb2tlbW9uLCBhcyB3ZWxsIGFzIGhvdyBtYW55IHRoZXJlIGFyZSBieSB1c2luZyBgbigpYCwgYW5kIHRoZW4gdXNpbmcgYGFycmFuZ2UoKWAgdG8gc2VlIHdoaWNoIHR5cGVzIGFyZSBvbiB0aGUgZmlyc3QgcG9zaXRpb25zOgoKYGBgIHtyfQpkYXRhICU+JQogIGdyb3VwX2J5KFR5cGUxKSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSwKICAgICAgICAgICAgYXZnX3RvdGFsID0gbWVhbihUb3RhbCksCiAgICAgICAgICAgIHNkX3RvdGFsID0gc2QoVG90YWwpKSAlPiUKICBhcnJhbmdlKGRlc2MoYXZnX3RvdGFsKSkKYGBgCgojIERyYWdvbiB0eXBlIGlzIHRoZSBiZXN0IQoKIVtdKGh0dHBzOi8vbWVkaWEuZ2lwaHkuY29tL21lZGlhL0hqbTl4ZmFReWlCQ0UvZ2lwaHkuZ2lmKQoKIyMjIEhvdyBtYW55IFBva2Vtb25zIGFyZSBwZXIgdHlwZT8KTGV0J3MgdXNlIHNvbWUgYGRwbHlyYCBmdW5jdGlvbnMgYW5kIGBnZ3Bsb3RgIHRvIGNyZWF0ZSBhIGJhcmNoYXJ0IG9mIFBva2Vtb24gdHlwZXMhCgpgYGB7cn0KZGF0YSAlPiUKICAgIGNvdW50KFR5cGUxKSAlPiUKICAgIG11dGF0ZShUeXBlMSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKFR5cGUxLCBuLCAuZGVzYyA9IEZBTFNFKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBUeXBlMSwgeSA9IG4pKSArIAogICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgYWVzKGZpbGwgPSBUeXBlMSkpICsgCiAgICAgIG15X3RoZW1lICsgCiAgICAgIGNvb3JkX2ZsaXAoKSArIAogICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjcCwgZ3VpZGUgPSBGQUxTRSkKICAKYGBgCgoKIyBFeGVyY2lzZXMKIVtdKGh0dHBzOi8vNjgubWVkaWEudHVtYmxyLmNvbS9kMThkYjMzZGViMjFhZjQ3Y2QwZjliMTllZjZmOThiYS90dW1ibHJfbjQ0dWs4a1lPeTF0dGhobGhvMV81MDAuZ2lmKQoKMS4gVXNlIHRoZSBgZmlsdGVyYCBmdW5jdGlvbiB0byBzZWxlY3Qgb25seSB0aGUgd2F0ZXIgUG9rZW1vbnMgYW5kIHNhdmUgaXQgaW4gYW4gb2JqZWN0IGNhbGxlZCBgd2F0ZXJgLgoyLiBEbyB0aGUgc2FtZSB3aXRoIHRoZSBmaXJlIFBva2Vtb25zIGFuZCBzYXZlIGl0IGluIGFuIG9iamVjdCBjYWxsZWQgYGZpcmVgLgozLiBXaGljaCB0eXBlIGlzIG1vcmUgcG93ZXJmdWw/IENhbGN1bGF0ZSB0aGUgYXZlcmFnZSBgVG90YWxgIHNjb3JlIG9mIGVhY2ggdHlwZSBvZiBQb2tlbW9uLiBVc2UgYG5hLnJtID0gVFJVRWAuIERvIG5vdCB1c2UgdGhlIGAlPiVgIG9wZXJhdG9yLgo0LiBUcnkgdG8gZ2V0IHRvIHRoZSBzYW1lIHJlc3VsdCBpbiBvbmUgcGlwZWxpbmUgYnkgdXNpbmcgYGdyb3VwX2J5YCwgYGZpbHRlcmAgYW5kIGBzdW1tYXJpemVgLgoKCiMgU29sdXRpb25zCjEuIFVzZSB0aGUgYGZpbHRlcmAgZnVuY3Rpb24gdG8gc2VsZWN0IG9ubHkgdGhlIHdhdGVyIFBva2Vtb25zIGFuZCBzYXZlIGl0IGluIGFuIG9iamVjdCBjYWxsZWQgYHdhdGVyYC4KYGBgIHtyIGVjaG8gPSBUUlVFfQp3YXRlciA8LSBkYXRhICU+JSAKICBmaWx0ZXIoVHlwZTEgPT0gIldhdGVyIikKCndhdGVyCmBgYAoKMi4gRG8gdGhlIHNhbWUgd2l0aCB0aGUgZmlyZSBQb2tlbW9ucyBhbmQgc2F2ZSBpdCBpbiBhbiBvYmplY3QgY2FsbGVkIGBmaXJlYC4KYGBgIHtyfQpmaXJlIDwtIGRhdGEgJT4lIAogIGZpbHRlcihUeXBlMSA9PSAiRmlyZSIpCmZpcmUKYGBgCmBgYCB7cn0KZmlyZSA8LSBkYXRhICU+JSAKICBmaWx0ZXIoVHlwZTEgPT0gIkZpcmUiKQpmaXJlCgoKYGBgCjMuIFdoaWNoIHR5cGUgaXMgbW9yZSBwb3dlcmZ1bD8gQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIGBUb3RhbGAgc2NvcmUgb2YgZWFjaCB0eXBlIG9mIFBva2Vtb24uIFVzZSBgbmEucm0gPSBUUlVFYC4gRG8gbm90IHVzZSB0aGUgYCU+JWAgb3BlcmF0b3IuCmBgYCB7cn0KbWVhbih3YXRlciRUb3RhbCwgbmEucm0gPSBUUlVFKQptZWFuKGZpcmUkVG90YWwsIG5hLnJtID0gVFJVRSkKYGBgCgo0LiBUcnkgdG8gZ2V0IHRvIHRoZSBzYW1lIHJlc3VsdCBpbiBvbmUgcGlwZWxpbmUgYnkgdXNpbmcgYGZpbHRlcmAsIGBncm91cF9ieWAgYW5kIGBzdW1tYXJpemVgLgpgYGB7cn0KZGF0YSAlPiUKICBmaWx0ZXIoVHlwZTEgPT0gIldhdGVyIiB8IFR5cGUxID09ICJGaXJlIikgJT4lCiAgZ3JvdXBfYnkoVHlwZTEpICU+JQogIHN1bW1hcmlzZShtZWFuKFRvdGFsLCBuYS5ybSA9IFRSVUUpKQpgYGAKCiMjIENvbmdyYXRzISBZb3UndmUgbGVhcm5lZCBkcGx5ciEKIVtdKGh0dHBzOi8vbWVkaWEuZ2lwaHkuY29tL21lZGlhL3loZlRZOEpMMXdJQUUvZ2lwaHkuZ2lmKQ==